/*     */ package com.zimbra.cs.account.ldap;
/*     */ 
/*     */ import com.google.common.cache.Cache;
/*     */ import com.google.common.cache.CacheBuilder;
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.DateUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.auth.PasswordUtil.SSHA512;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Date;
/*     */ import java.util.HashMap;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.concurrent.Callable;
/*     */ import java.util.concurrent.ExecutionException;
/*     */ import java.util.concurrent.TimeUnit;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class LdapLockoutPolicy
/*     */ {
/*     */   private String[] mFailures;
/*     */   private List<String> mFailuresToRemove;
/*     */   private Provisioning mProv;
/*     */   private Account mAccount;
/*     */   private boolean mEnabled;
/*     */   private long mMaxFailures;
/*     */   private boolean mLockoutExpired;
/*     */   private boolean mIsLockedOut;
/*     */   private String mAccountStatus;
/*     */   
/*     */   public LdapLockoutPolicy(Provisioning prov, Account account)
/*     */     throws ServiceException
/*     */   {
/*  54 */     this.mAccount = account;
/*  55 */     this.mProv = prov;
/*  56 */     this.mAccountStatus = account.getAccountStatus(prov);
/*  57 */     this.mMaxFailures = this.mAccount.getLongAttr("zimbraPasswordLockoutMaxFailures", 0L);
/*  58 */     this.mEnabled = ((this.mMaxFailures > 0L) && (this.mAccount.getBooleanAttr("zimbraPasswordLockoutEnabled", false)));
/*  59 */     this.mFailures = this.mAccount.getMultiAttr("zimbraPasswordLockoutFailureTime");
/*  60 */     this.mIsLockedOut = computeIsLockedOut();
/*     */   }
/*     */   
/*     */   private boolean computeIsLockedOut() throws ServiceException
/*     */   {
/*  65 */     if (!this.mEnabled) { return false;
/*     */     }
/*  67 */     Date locked = this.mAccount.getGeneralizedTimeAttr("zimbraPasswordLockoutLockedTime", null);
/*     */     
/*     */ 
/*  70 */     if (locked == null) { return false;
/*     */     }
/*     */     
/*  73 */     long duration = this.mAccount.getTimeInterval("zimbraPasswordLockoutDuration", 0L);
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*  79 */     if ((duration != 0L) && (System.currentTimeMillis() > locked.getTime() + duration)) {
/*  80 */       this.mLockoutExpired = true;
/*  81 */       return false;
/*     */     }
/*     */     
/*     */ 
/*  85 */     return this.mAccountStatus.equalsIgnoreCase("lockout");
/*     */   }
/*     */   
/*     */   public boolean isLockedOut() {
/*  89 */     return this.mIsLockedOut;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private int updateFailureTimes(Map<String, Object> attrs)
/*     */   {
/* 103 */     long duration = this.mAccount.getTimeInterval("zimbraPasswordLockoutFailureLifetime", 0L);
/* 104 */     if (duration != 0L) {
/* 105 */       String expiredTime = DateUtil.toGeneralizedTime(new Date(System.currentTimeMillis() - duration));
/* 106 */       for (String failure : this.mFailures) {
/* 107 */         if (failure.compareTo(expiredTime) < 0) {
/* 108 */           if (this.mFailuresToRemove == null) this.mFailuresToRemove = new ArrayList();
/* 109 */           this.mFailuresToRemove.add(failure);
/*     */         }
/*     */       }
/*     */     }
/*     */     
/* 114 */     String currentFailure = DateUtil.toGeneralizedTime(new Date());
/*     */     
/* 116 */     boolean removeOldest = (this.mFailures.length == this.mMaxFailures) && (this.mFailuresToRemove == null);
/* 117 */     if (removeOldest) {
/* 118 */       int j = 0;
/* 119 */       for (int i = 1; i < this.mFailures.length; i++) {
/* 120 */         if (this.mFailures[i].compareTo(this.mFailures[j]) < 0) {
/* 121 */           j = i;
/*     */         }
/*     */       }
/*     */       
/*     */ 
/* 126 */       for (String f : this.mFailures) {
/* 127 */         if (f.equalsIgnoreCase(currentFailure)) {
/* 128 */           removeOldest = false;
/* 129 */           break;
/*     */         }
/*     */       }
/* 132 */       if (removeOldest) attrs.put("-zimbraPasswordLockoutFailureTime", this.mFailures[j]);
/* 133 */     } else if (this.mFailuresToRemove != null)
/*     */     {
/* 135 */       attrs.put("-zimbraPasswordLockoutFailureTime", this.mFailuresToRemove);
/*     */     }
/*     */     
/*     */ 
/* 139 */     attrs.put("+zimbraPasswordLockoutFailureTime", currentFailure);
/*     */     
/*     */ 
/* 142 */     return 1 + this.mFailures.length - (removeOldest ? 1 : 0) - (this.mFailuresToRemove == null ? 0 : this.mFailuresToRemove.size());
/*     */   }
/*     */   
/*     */   public void successfulLogin() {
/* 146 */     if (!this.mEnabled) return;
/* 147 */     Map<String, Object> attrs = new HashMap();
/* 148 */     if (this.mFailures.length > 0)
/* 149 */       attrs.put("zimbraPasswordLockoutFailureTime", "");
/* 150 */     if (this.mLockoutExpired) {
/* 151 */       if (this.mAccountStatus.equalsIgnoreCase("lockout")) {
/* 152 */         ZimbraLog.security.info(ZimbraLog.encodeAttrs(new String[] { "cmd", "Auth", "account", this.mAccount.getName(), "info", "account re-activated from lockout status upon successful login" }));
/*     */         
/*     */ 
/* 155 */         attrs.put("zimbraAccountStatus", "active");
/*     */       }
/* 157 */       attrs.put("zimbraPasswordLockoutLockedTime", "");
/*     */     }
/*     */     try
/*     */     {
/* 161 */       if (attrs.size() > 0)
/* 162 */         this.mProv.modifyAttrs(this.mAccount, attrs);
/*     */     } catch (Exception e) {
/* 164 */       ZimbraLog.account.warn("Unable to update account password lockout attrs: " + this.mAccount.getName(), e);
/*     */     }
/*     */   }
/*     */   
/* 168 */   private static class PasswordLockoutCache { private static long maxCacheSize = DebugConfig.invalidPasswordMaxCacheSize;
/* 169 */     private static int cacheExpiryInMinute = DebugConfig.invalidPasswordCacheExpirationInMinutes;
/* 170 */     private static Cache<String, List<String>> cache = CacheBuilder.newBuilder().maximumSize(maxCacheSize).expireAfterWrite(cacheExpiryInMinute, TimeUnit.MINUTES).build();
/*     */     
/*     */     private static boolean suppressPasswordLockOut(Account acct, String protocol, String password)
/*     */     {
/* 174 */       if ((!StringUtil.isNullOrEmpty(password)) && (!StringUtil.isNullOrEmpty(protocol)) && 
/* 175 */         (LC.zimbra_password_lockout_suppression_enabled.booleanValue())) {
/* 176 */         for (String suppressionProtocol : LC.zimbra_password_lockout_suppression_protocols.value().split(",")) {
/* 177 */           suppressionProtocol = suppressionProtocol.trim();
/* 178 */           if (protocol.equalsIgnoreCase(suppressionProtocol)) {
/* 179 */             List<String> pwds = null;
/*     */             try {
/* 181 */               pwds = (List)cache.get(acct.getId(), new Callable()
/*     */               {
/*     */                 public List<String> call() throws Exception {
/* 184 */                   return new ArrayList();
/*     */                 }
/*     */               });
/*     */             } catch (ExecutionException e) {
/* 188 */               ZimbraLog.account.warn("Error while retrieving invalid password cache entry", e);
/* 189 */               return false;
/*     */             }
/* 191 */             synchronized (pwds) {
/* 192 */               int cacheSize = pwds.size();
/* 193 */               if (cacheSize == 0) {
/* 194 */                 pwds.add(PasswordUtil.SSHA512.generateSSHA512(password, null));
/* 195 */                 ZimbraLog.account.debug("Created entry in password lockout cache");
/*     */               } else {
/* 197 */                 for (String pwd : pwds) {
/* 198 */                   if (PasswordUtil.SSHA512.verifySSHA512(pwd, password)) {
/* 199 */                     return true;
/*     */                   }
/*     */                 }
/* 202 */                 int maxCacheSize = LC.zimbra_password_lockout_suppression_cache_size.intValue();
/* 203 */                 ZimbraLog.account.debug("Password lockout suppression cache size = %s (max = %s)", new Object[] { Integer.valueOf(cacheSize), Integer.valueOf(maxCacheSize) });
/* 204 */                 if (cacheSize < maxCacheSize) {
/* 205 */                   pwds.add(PasswordUtil.SSHA512.generateSSHA512(password, null));
/* 206 */                   ZimbraLog.account.debug("Added entry in password lockout cache");
/*     */                 }
/*     */               }
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */       
/* 214 */       return false;
/*     */     }
/*     */   }
/*     */   
/*     */   public void failedLogin() {
/* 219 */     failedLogin(null, null);
/*     */   }
/*     */   
/*     */   public void failedLogin(String protocol, String password) {
/* 223 */     if (!this.mEnabled) { return;
/*     */     }
/* 225 */     if (PasswordLockoutCache.suppressPasswordLockOut(this.mAccount, protocol, password)) {
/* 226 */       ZimbraLog.security.info("Suppressed password lockout.");
/* 227 */       return;
/*     */     }
/*     */     
/* 230 */     Map<String, Object> attrs = new HashMap();
/*     */     
/* 232 */     int totalFailures = updateFailureTimes(attrs);
/*     */     
/* 234 */     if ((totalFailures >= this.mMaxFailures) && (!this.mIsLockedOut)) {
/* 235 */       ZimbraLog.security.info(ZimbraLog.encodeAttrs(new String[] { "cmd", "Auth", "account", this.mAccount.getName(), "error", "account lockout due to too many failed logins" }));
/*     */       
/* 237 */       attrs.put("zimbraPasswordLockoutLockedTime", DateUtil.toGeneralizedTime(new Date()));
/* 238 */       attrs.put("zimbraAccountStatus", "lockout");
/*     */     }
/*     */     try
/*     */     {
/* 242 */       this.mProv.modifyAttrs(this.mAccount, attrs);
/*     */     } catch (Exception e) {
/* 244 */       ZimbraLog.account.warn("Unable to update account password lockout attrs: " + this.mAccount.getName(), e);
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/account/ldap/LdapLockoutPolicy.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */